<?php

class MyModel extends CActiveRecord
{
    // {{{ Members
    /**
     * @var string
     */
    var $nameFields = "id";
    /**
     * @var string
     */
    var $nameFormat = "{1}";
    /**
     * Does this model use record revisions?
     * @var bool
     */
    var $usesRevision   = false;

    /**
     * Revision number of current record
     * @var int
     */
    var $recordRevision;

    /**
     * Does this model use logging?
     * @var bool
     */
    var $usesLog        = false;

    /**
     * Prepare date attributes on save?
     * 
     * @var mixed
     * @see MyModel::save
     * @access public
     */
    public $datesToDB = true;

    /**
     * Prepare numeric attributes on save?
     * 
     * @var mixed
     * @see MyModel::save
     * @access public
     */
    public $prepareNumericAttributesOnSave = true;

    // }}} 
    // {{{ getRecordName
    public function getRecordName()
    {
        if( !isset($this->nameFields) or !isset($this->nameFormat) )
            return '';
        $aFields = explode(';', $this->nameFields);
        $name=$this->nameFormat;
        for( $i=0; $i<count($aFields); $i++ ) {
            $name = str_replace( '{'.($i+1).'}', $this->$aFields[$i], $name );
        }
        return $name;
    } // }}} 
    // {{{ behaviors
    public function behaviors() {
        return array(
            'ERememberFiltersBehavior' => array(
                'class' => 'ERememberFiltersBehavior',
                'defaults'=>array(),           /* optional line */
                'defaultStickOnClear'=>false   /* optional line */
            ),
        );
    } // }}} 
    // {{{ checkDateNotEmpty
    /**
     * Validates if a date is not '0000-00-00'
     * 
     * @param string $attribute Name of attribute
     * @param mixed $params Additional parameters
     * @access public
     * @return void
     */
    public function checkDateNotEmpty($attribute,$params)
    {
        if($this->$attribute=='0000-00-00')
            $this->addError($attribute,Yii::t('site','Please enter a date as {attributeLabel}',array('{attributeLabel}'=>$this->getAttributeLabel($attribute))));
    } // }}} 
    // {{{ checkDate
    public function checkDate($attribute,$params)
    {
        $dateFormat =  CLocale::getInstance(Yii::app()->language)->getDateFormat('medium');
        //echo "<li>dateFormat: $dateFormat";
        //echo "<li>attribute: {$this->$attribute}";
        if(CDateTimeParser::parse( $this->$attribute, $dateFormat)==false)
            $this->addError($attribute,Yii::t('site','Please enter a valid date as {attribute}.',array('{attribute}'=>$this->getAttributeLabel($attribute))));
    } // }}} 
    // {{{ save
    public function save($runValidation=true, $attributes=null)
    {
        if($this->datesToDB)
            $this->_prepareDatesToDB();
        if($this->prepareNumericAttributesOnSave)
            $this->_prepareNumericAttributes();
        return parent::save($runValidation, $attributes );
    } 
    // }}}
    // {{{ afterSave 
    /**
     * After saving of the model data, check if
     * - log entry should be added
     * - revision should be saved
     *
     * @return void
     */
    /*
    protected function afterSave()
    {
        // Use record log?
        if( $this->usesLog ) 
            $this->addLog();

        // Add a new revision?
        if( $this->usesRevision ) 
            $this->saveRevision();

        parent::afterSave();
    }
     */
    // }}}
    // {{{ *** Record Revisions ***
    // {{{ saveRevision
    /**
     * Saves a new revision of the current record
     */
    protected function saveRevision()
    {
        $revision                       = new RecordRevision;
        $revision->recordTableName      = $this->tableName();
        $revision->foreignKey           = $this->id;
        $revision->revisionNbr          = $this->getCurrentRevisionNumber()+1;
        $revision->revisionTimestamp    = time();
        $revision->recordData           = serialize($this->attributes);
        $revision->save(); 
    } // }}} 
    // {{{ getRecordRevisions
    /**
     * Gets all revisions of a record
     */
    public function getRecordRevisions()
    {
        $sql = "SELECT * FROM RecordRevision rl "
            ."WHERE recordTableName=:table "
            ."AND foreignKey=:fk "
            ."ORDER BY revisionNbr DESC";
        $command = Yii::app()->db->createCommand( $sql );
        $command->bindParam( ":table", $this->tableName() );
        $command->bindParam( ":fk", $this->id );
        $rows = $command->queryAll();
        return $rows;
    } // }}} 
    // {{{ getRevision
    /**
     * Get a specific revision of a record
     *
     * @param   int     $id Record      primary key
     * @param   int     $revisionNbr    Revision Number
     * @return  mixed
     */
    public function &getRevision( $id, $revisionNbr )
    {
        echo "<li>id: $id, revisionNbr: $revisionNbr";
        $revision = RecordRevision::model()->findByAttributes(
            array(
                'recordTableName'   => $this->tableName(),
                'foreignKey'        => $id,
                'revisionNbr'       => $revisionNbr
            )
        );
        $recordData = array();
        $recordData = unserialize(str_replace(array("\r\n","\r","\n"),array("CRLF","CR","LF"),$revision->recordData));
        if( $recordData==false )
            $recordData = 'ERROR';
        
        $modelName = $revision->recordTableName;
        $model = new $modelName;
        foreach( $recordData as $key=>$value )
            $model->$key = str_replace(array("CRLF","CR","LF"),array("\r\n","\r","\n"),$value);
        $model->recordRevision = $revisionNbr;
        
        return $model; 
    } // }}} 
    // {{{ getCurrentRevisionNumber
    /**
     * Gets the current (highest) revision number of a record
     */
    public function getCurrentRevisionNumber()
    {
        $sql = "SELECT MAX(revisionNbr) AS revisionNumber FROM RecordRevision WHERE recordTableName=:recordTableName AND foreignKey=:foreignKey";
        $command = Yii::app()->db->createCommand($sql);
        $command->bindParam(":recordTableName", $this->tableName(),PDO::PARAM_STR);
        $command->bindParam(":foreignKey", $this->id);
        $row = $command->queryRow();
        $revisionNumber = $row['revisionNumber'];
        if( $revisionNumber=='' )
            $revisionNumber = 0;
        return $revisionNumber;
    } // }}} 
    // }}} 
    // {{{ *** Record Log ***
    // {{{ addLog
    /**
     * Adds a log entry for a record
     */
    public function addLog()
    {
	$log = new RecordLog;
        $log->recordTableName   = $this->tableName();
        $log->foreignKey        = $this->id;
        $log->eventType         = $this->isNewRecord ? 'create' : 'update';
        $log->userId            = Yii::app()->user->id;
        $log->eventTime         = time();
        $log->save();
    } // }}} 
    // {{{ getRecordLog
    /**
     * Gets the log for a record
     *
     * @return mixed
     */
    public function getRecordLog()
    {
        $sql = "SELECT rl.*, u.* FROM RecordLog rl "
            ."LEFT JOIN User u ON rl.userId=u.id "
            ."WHERE recordTableName=:table "
            ."AND foreignKey=:fk "
            ."ORDER BY rl.eventTime DESC";
        $command = Yii::app()->db->createCommand( $sql );
        $command->bindParam( ":table", $this->tableName() );
        $command->bindParam( ":fk", $this->id );
        $rows = $command->queryAll();
        return $rows;
    } // }}} 
    // }}} 
    // {{{ _prepareDatesToDB
    /**
     * Prepares all date attributes to an ISO format (YYYY-MM-DD)
     * 
     * @param bool $preserveEmpty TRUE if empty attribute should be preserved empty
     * @access public
     * @return void
     */
    public function _prepareDatesToDB($preserveEmpty=false)
    {
        //$dateFormat = CLocale::getInstance(Yii::app()->language)->getDateFormat('medium');
        $dateFormatFrom = Yii::app()->locale->getDateFormat('small');
        // DEBUG echo "<li>dateFormat. $dateFormatFrom";
        foreach( $this->getTableSchema()->columns as $column ) {
            if( $column->dbType=='date' ) {
                // DEBUG echo "<li>column {$column->name}: type {$column->dbType}";
                $columnName = $column->name;
                // DEBUG echo "<li>column $columnName: value {$this->$columnName}";
                if( $this->$columnName=='' ) {
                    if(!$preserveEmpty)
                        $this->$columnName='0000-00-00';
                } else {
                    //$this->$columnName = date("Y-m-d", CDateTimeParser::parse( $this->$columnName, $dateFormat ));
                    $this->$columnName = Yii::app()->dateFormatter->formatDateTime(
                        CDateTimeParser::parse(
                            $this->$columnName,
                            $dateFormatFrom
                        ),
                        'database',
                        false
                    );
                }
                // DEBUG echo "&rArr; ".$this->$columnName;
            }
        }
    }
    // }}} 
    // {{{ _restoreDateAttributes
    /**
     * Restores Date Attributes according to locale
     * 
     * @access public
     * @return void
     */
    public function _restoreDateAttributes()
    {
        $schema = $this->getTableSchema();
        $dateFormatter = Yii::app()->dateFormatter;
        foreach( $schema->columns as $column ) {
            if( $column->dbType=='date' ) {
		$columnName =  $column->name;
                // DEBUG echo "<li>$columnName: ".$model->$columnName;
                if( $this->$columnName=='0000-00-00' ) {
		    $this->$columnName = '';
		} elseif(trim($this->$columnName)=='') {
		    $this->$columnName='';
                } else {
		    list($year,$month,$day) = explode( '-', $this->$columnName );
		    //echo "<li>year: $year, month: $month, day: $day";
                    $this->$columnName = $dateFormatter->formatDateTime( 
                        mktime(0,0,0,$month,$day,$year),'medium',null
                    );
                }
            }
        }
    } // }}} 
    // {{{ _prepareNumericAttributes
    public function _prepareNumericAttributes()
    {
        foreach( $this->getTableSchema()->columns as $column ) {
            if( preg_match("/decimal|float/", $column->dbType ) ) {
                $columnName = $column->name;
                $this->$columnName = str_replace(',','.',$this->$columnName);
            }
        }
    } // }}} 
    // {{{  getDistinctColumnValues
    /**
     * Gets an array of distinct column values 
     * 
     * @param mixed $key    Attribute to be used as array key
     * @param mixed $value  Attribute to be used as value
     * @access public
     * @return mixed Array of distinct $value attributes, indexed by $key attributes
     */
    public function getDistinctColumnValues($key, $value=null, $condition=null)
    {
        if($value==null) $value = $key;
        $criteria = new CDbCriteria;
        $criteria->distinct = true;
        if(is_string($value)) {
            $criteria->select = array($key,$value);
            $criteria->order = $value;
        } else {
            $criteria->select = array_merge(array($key),$value);
            $criteria->order = join(',',$value);
        }
        if(!is_null($condition))
            $criteria->addCondition($condition);
        $models = $this->findAll($criteria);
        $result = array();
        foreach($models as $model) {
            // DEBUG echo par($model->attributes);
            if(is_string($value))
                $result[$model->$key] = $model->$value;
            else {
                $tmp = array();
                foreach($value as $attribute)
                    $tmp[] = $model->$attribute;
                $result[$model->$key] = join( ' - ',$tmp);
            }

        }
        return $result;
    } // }}} 
    // {{{ addNote
    /**
     * Adds a new note to this model.
     * This method will set tableName and foreignKey of the note accordingly.
     * @param Note the note to be added
     * @return boolean whether the note is saved successfully
     */
    public function addNote($note)
    {
        $note->tableName = $this->getTableNamePrepared();
        $note->foreignKey=$this->getAttribute($this->tableSchema->primaryKey);
        return $note->save();
    } // }}} 
    // {{{ getTableNamePrepared
    /**
     * Returns the table name, having '{{...}}' replaced with DB table prefix 
     * 
     * @param string $tableName If null, current model's table name will be used
     * @access public
     * @return string Prepared table name
     */
    public function getTableNamePrepared($tableName=null)
    {
        if($tableName==null)
            $tableName = $this->tableName();
        if(preg_match("/^{{(.*)}}$/", $tableName,$matches)) {
            return Yii::app()->db->tablePrefix.$matches[1];
        } else {
            return $tableName;
        }
    } // }}} 
    // {{{ getNotesAjaxLink
    /**
     * Gets a CHtml::link to show the Notes items 
     * 
     * @access public
     * @param string $itemName Item name
     * @param int $notesCount Number of notes for model 
     * @return CHtml::link
     */
    public function getNotesAjaxLink($itemName, $notesCount=0)
    {
        if($notesCount==0 ) {
            return 0;
            /*
            return CHtml::link(
                '0',
                array(
                    '/note/create',
                    $this->tableSchema->primaryKey=>$this->primaryKey
                ),
                array(
                    'title'=>Yii::t('site','Add a new Note')
                )
            );
             */
        } else {
            return CHtml::ajaxLink(
                $notesCount,
                array(
                    'note/popupList',
                    'itemName'=>$itemName,
                    'Note[tableName]'=>$this->getTableNamePrepared(),
                    'Note[foreignKey]'=>$this->primaryKey,
                    'popup'=>1
                ),
                array(
                    'onclick'=>'$("#notesDialog").dialog("open"); return false;',
                    'update'=>'#notesDialog',
                ),
                array(
                    'title' => Yii::t('site','Show Notes for Item {recordName} as popup',array('{recordName}'=>$this->recordName))
                )
            );
        }
    } // }}}
    // {{{ getAttachments
    /**
     * Gets a list of attachments for this record
     * 
     * @access public
     * @return void
     */
    public function getAttachments()
    {
        $dir = Yii::app()->basePath . '/data/'.get_class($this).'/'.$this->primaryKey;
        if(!is_dir($dir))
            return array();
        $files = CFileHelper::findFiles($dir);
        $result = array();
        foreach($files as $file) {
            $file = array(
                'path'  => str_replace("\\","/",$file),
                'url'   => 'protected/data/'.get_class($this).'/'.$this->primaryKey.'/'.basename(str_replace("\\","/",$file))
            );
            $result[] = $file;
        }
        return $result;
    } // }}} 
    // {{{ replaceAttributeLabels
    /**
     * Replaces all attribute names with labels in a string
     * 
     * @param mixed $string String with attribute labels
     * @access public
     * @return The string with replaced attributes
     */
    public function replaceAttributeLabels($string)
    {
        $labels = $this->attributeLabels();
        foreach($labels as $attribute=>$label)
            $string = str_replace($attribute,$label,$string);
        return $string;
    } // }}}The string with replaced attributes 
    // {{{ getStatuslistTranslated
    /**
     * Gets a translated simpleWorkflow status list
     * 
     * @param mixed $statusList SWHelper status list
     * @param mixed $translations Array of translations, indexed by SWStatus keys
     * @access public
     * @return mixed
     */
    public function getStatuslistTranslated($statusList,$translations)
    {
        foreach($statusList as $key=>$value) {
            list($workflow,$node) = explode('/',$key);
            // DEBUG echo "<li>workflow: $workflow, node: $node";
            if(array_key_exists($key,$translations))
                $statusList[$key] = str_replace($node,$translations[$key],$statusList[$key]);
        }
        return $statusList;
    } // }}} 
    // {{{ getYesNoOptions
    public function getYesNoOptions()
    {
        return array(
            1 => Yii::t('site','Yes'),
            0 => Yii::t('site','No')
        );
    } // }}} 
        // {{{ suggestItems
	/**
	 * Suggests a list of existing items matching the specified keyword.
	 * @param string the model name to be searched
	 * @param string the model attribute to be searched
	 * @param string the keyword to be matched
	 * @param integer maximum number of tags to be returned
	 * @return array list of matching tag names
	 */
	public function suggestItems($model,$modelAttribute,$keyword,$limit=20)
        {
                //Yii::log("model: $model, modelAttribute: $modelAttribute, keyword: $keyword", 'info', "MyModel/suggestItems");
                $items=$this->findAll(
                    array(
			'condition'=>$modelAttribute.' LIKE :keyword',
			'order'=>$modelAttribute,
			'limit'=>$limit,
                        'params'=>array(
				':keyword'=>'%'.strtr($keyword,array('*'=>'%', '%'=>'\%', '_'=>'\_', '\\'=>'\\\\')).'%',
			),
		    )
                );
		$suggestions=array();
                foreach($items as $item) {
                    //echo $item->$modelAttribute;
    		    $suggestions[]=$item->$modelAttribute;
                }
		return array_unique($suggestions);
        } // }}} 
}
?>
